/*************************************************************************
*        Author       : xuheng
************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <netdb.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include <errno.h>
#include <setjmp.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
#include <assert.h> 

#include "Apisockcomm_nonb.h"

/****************************************************************************
* function      :SendApi_nonb
* description   :send packet to Api entity noblock
* parameters    :Sid - socket handle
* return        : 0           -success
* return        : 1           -success but incomplete
*               :-1           -socket error
*               :-2           -connection closed
****************************************************************************/
int SendApi_nonb(int sd, FRAME* frame)
{
	int ret = 0;
	frame->maxsize = strlen(frame->pBuf + frame->curPos) + 1;
	int iWantLen = frame->maxsize - frame->curPos;

	if(iWantLen > 0)
	{
		int ret = send(sd, frame->pBuf + frame->curPos, iWantLen, 0);
		if(ret < 0) //error
			return -1;
		else if(ret == 0) //closed
			return -2;
		else //this times ok
		{
			frame->curPos += ret;
			if(ret == iWantLen){//total finished
				frame->curPos = 0;
				return 0;
			}
			else{
				return 1;
			}
		}
	}
}

int checkFrame(FRAME* frame)
{
	if(frame->curPos > 10)
		return 0;
	else 
		return -1;
}
/****************************************************************************
* function      :RecvApi
* description   :recv package from Api entity, do not block
* parameters    :Sid - socket handle
* return        : 0           -success
*               : 1           -need data, incomplete 
*               :-1           -socket error
*               :-2           -connection closed
*								:-3						-buf overflow
****************************************************************************/
int RecvApi_nonb(int sd, FRAME* frame)
{
	int ret = 0;
	int iWantLen = frame->maxsize - frame->curPos -1;
	if(iWantLen > 0)
	{
		ret = recv(sd, frame->pBuf + frame->curPos, iWantLen, 0);
		if(ret < 0){
			return -1;	//error
		}
		else if(ret == 0){
			return -2;	//closed
		}
		else// this times read success
		{
			frame->curPos += ret;
			if(!checkFrame(frame)){
				frame->curPos = 0;
				return 0;
			}
			else{
				return 1;
			}
		}
	}
	else
	{
		return -3;
	}
}

int connect_nonb(int sockfd, struct sockaddr *saptr, int salen, int nsec)
{
	int			flags, n, error;
	socklen_t		len;
	fd_set		rset, wset;
	struct timeval	tval;

	flags = fcntl(sockfd, F_GETFL, 0);
	fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);

	error = 0;
	if ( (n = connect(sockfd, (struct sockaddr *) saptr, salen)) < 0)
		if (errno != EINPROGRESS)
			return(-1);

	/* Do whatever we want while the connect is taking place. */
	if (n == 0)
		goto done;	/* connect completed immediately */

	FD_ZERO(&rset);
	FD_SET(sockfd, &rset);
	wset = rset;
	tval.tv_sec = nsec;
	tval.tv_usec = 0;

	if ( (n = select(sockfd+1, &rset, &wset, NULL, nsec ? &tval : NULL)) == 0) {
		close(sockfd);		/* timeout */
		errno = ETIMEDOUT;
		return(-1);
	}

	if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
		len = sizeof(error);
		if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0)
			return(-1);			/* Solaris pending error */
	}

done:
	fcntl(sockfd, F_SETFL, flags);/* restore file status flags */
	if (error) {
		close(sockfd);/* just in case */
		errno = error;
		return(-1);
	}
	return(0);
}
